package com.basic.business.finance.service.impl;

import cn.idev.excel.EasyExcel;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.read.listener.ReadListener;
import cn.idev.excel.util.ListUtils;
import com.basic.business.finance.domain.TAgcPayMoneyDetails;
import com.basic.business.finance.domain.TAliPayMoneyDetails;
import com.basic.business.finance.domain.TPddPayMoneyDetails;
import com.basic.business.finance.mapper.TMoneyDetailsMapper;
import com.basic.business.finance.mapper.TMoneyMainMapper;
import com.basic.business.finance.service.ITMoneyMainService;
import com.basic.business.finance.service.ITMoneySummaryService;
import com.basic.business.store.domain.TStoreMgmt;
import com.basic.common.constant.CacheConstants;
import com.basic.common.core.redis.RedisCacheUtils;
import com.basic.common.enums.BusinessStatus;
import com.basic.common.utils.DateUtils;
import com.basic.common.utils.SecurityUtils;
import com.basic.common.utils.StringUtils;
import com.basic.common.websocket.WebSocketUsers;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import com.basic.common.core.service.impl.BaseServiceImpl;
import com.basic.business.finance.domain.TMoneyMain;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cn.idev.excel.support.ExcelTypeEnum.CSV;
import static cn.idev.excel.support.ExcelTypeEnum.XLSX;

/**
 * 账单明细Service业务层处理
 *
 * @author zhaoxy_jn@163.com
 */
@Service
public class TMoneyMainServiceImpl extends BaseServiceImpl<TMoneyMainMapper,TMoneyMain> implements ITMoneyMainService {

    private static final int BATCH_COUNT = 500;
    private static final String ALIPAY_PLATFORM = "1";
    private static final String PDD_PLATFORM = "2";
    private static final String AGC_PLATFORM = "3";
    private static final Charset GBK_CHARSET = Charset.forName("GBK");

    @Resource
    private TMoneyMainMapper tMoneyMainMapper;

    @Resource
    private TMoneyDetailsMapper detailsMapper;

    @Resource
    private ITMoneySummaryService summaryService;

    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor exec;


    @Override
    public int deleteByIds(Object[] ids) {
        CompletableFuture.runAsync(() -> detailsMapper.deleteMainIds(ids));
        CompletableFuture.runAsync(() -> summaryService.deleteMainIds(ids));
        return super.deleteByIds(ids);
    }

    @Async
    @Transactional
    @Override
    public void importCsv(MultipartFile[] files, String rulePlatform) throws InterruptedException {


        try {
            for (MultipartFile file : files) {
                // 上传excel的名称
                String excelName = file.getOriginalFilename();
                if (excelName == null) {
                    continue; // 或抛出异常
                }

                // 支付宝
                if (StringUtils.equals(rulePlatform, ALIPAY_PLATFORM)) {
                    // 通过上传Excel的文件名称获取店铺账号
                    int underscoreIndex = excelName.indexOf("_");
                    if (underscoreIndex <= 0) {
                        continue; // 或抛出异常
                    }
                    String storeCode = excelName.substring(0, underscoreIndex);

                    // 账单日期
                    AtomicReference<String> billDate = new AtomicReference<>(null);

                    TMoneyMain main = createMainRecord(ALIPAY_PLATFORM, excelName, storeCode);

                    Runnable run = () -> {
                        try (InputStream inputStream = file.getInputStream()) {
                            EasyExcel.read(inputStream, TAliPayMoneyDetails.class, new ReadListener<TAliPayMoneyDetails>() {
                                /**
                                 *临时存储
                                 */
                                private List<TAliPayMoneyDetails> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                                @Override
                                public void invoke(TAliPayMoneyDetails data, AnalysisContext analysisContext) {
                                    if(!StringUtils.isEmpty(data.getBusinessType())) {
                                        // 截取发生日期为账单日期
                                        billDate.set(DateUtils.dateToYM(data.getCreateTime()));

                                        data.setMainId(main.getId());
                                        cachedDataList.add(data);
                                        if (cachedDataList.size() >= BATCH_COUNT) {
                                            saveData();
                                            // 存储完成清理 list
                                            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                                        }
                                    }
                                }

                                @Override
                                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                                    saveData();
                                }

                                // 保存数据库
                                private void saveData() {
                                    if (!cachedDataList.isEmpty()) {
                                        detailsMapper.batchInsert(cachedDataList);
                                    }
                                }
                            }).excelType(CSV).charset(GBK_CHARSET).sheet().headRowNumber(5).doRead();

                            // 更新账单状态
                            main.setStatus("3");
                            main.setBillDate(billDate.get());
                            tMoneyMainMapper.update(main);
                        } catch (Exception e) {
                            main.setStatus("2");
                            tMoneyMainMapper.update(main);
                            // 通过websocket发送通知
                            WebSocketUsers.sendMessageToUserByText(main.getUserId(), excelName + " 账单上传失败，请重新上传", BusinessStatus.SUCCESS);
                            throw new RuntimeException("解析支付宝账单出错，请重新上传");
                        }

                        // 通过websocket发送通知
                        WebSocketUsers.sendMessageToUserByText(main.getUserId(), excelName + " 账单上传完成", BusinessStatus.SUCCESS);

                        // 生成分类账单数据
                        summaryService.classifyMoney(main);
                    };
                    exec.execute(run);
                } else if (StringUtils.equals(rulePlatform, PDD_PLATFORM)) {

                    // 店铺账号
                    String storeCode = Objects.requireNonNull(getFileName(file.getOriginalFilename()));

                    // 账单日期
                    AtomicReference<String> billDate = new AtomicReference<>(null);

                    TMoneyMain main = createMainRecord(PDD_PLATFORM, excelName, storeCode);

                    Runnable run = () -> {
                        try (InputStream inputStream = file.getInputStream()) {
                            EasyExcel.read(inputStream, TPddPayMoneyDetails.class, new ReadListener<TPddPayMoneyDetails>() {
                                /**
                                 *临时存储
                                 */
                                private List<TPddPayMoneyDetails> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                                @Override
                                public void invoke(TPddPayMoneyDetails data, AnalysisContext analysisContext) {
                                    if(!StringUtils.isEmpty(data.getBusinessType())) {
                                        // 截取发生日期为账单日期
                                        billDate.set(DateUtils.dateToYM(data.getCreateTime()));

                                        data.setMainId(main.getId());
                                        cachedDataList.add(data);
                                        if (cachedDataList.size() >= BATCH_COUNT) {
                                            saveData();
                                            // 存储完成清理 list
                                            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                                        }
                                    }
                                }

                                @Override
                                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                                    saveData();
                                }

                                // 保存数据库
                                private void saveData() {
                                    if (!cachedDataList.isEmpty()) {
                                        detailsMapper.batchInsert(cachedDataList);
                                    }
                                }
                            }).excelType(CSV).charset(GBK_CHARSET).sheet().headRowNumber(5).doRead();

                            // 更新账单状态
                            main.setStatus("3");
                            main.setBillDate(billDate.get());
                            tMoneyMainMapper.update(main);
                        } catch (Exception e) {
                            e.printStackTrace();
                            main.setStatus("2");
                            tMoneyMainMapper.update(main);
                            // 通过websocket发送通知
                            WebSocketUsers.sendMessageToUserByText(main.getUserId(), excelName + " 账单上传失败，请重新上传", BusinessStatus.SUCCESS);
                            throw new RuntimeException("解析拼多多账单出错，请重新上传");
                        }

                        // 通过websocket发送通知
                        WebSocketUsers.sendMessageToUserByText(main.getUserId(), excelName + " 账单上传完成", BusinessStatus.SUCCESS);

                        // 生成分类账单数据
                        summaryService.classifyMoney(main);

                    };
                    exec.execute(run);


                } else if (StringUtils.equals(rulePlatform, AGC_PLATFORM)) {
                    // 店铺账号
                    String storeCode = Objects.requireNonNull(getAgcFileName(file.getOriginalFilename()));

                    // 账单日期
                    AtomicReference<String> billDate = new AtomicReference<>(null);

                    TMoneyMain main = createMainRecord(AGC_PLATFORM, excelName, storeCode);

                    Runnable run = () -> {
                        try (InputStream inputStream = file.getInputStream()) {
                            EasyExcel.read(inputStream, TAgcPayMoneyDetails.class, new ReadListener<TAgcPayMoneyDetails>() {
                                /**
                                 *临时存储
                                 */
                                private List<TAgcPayMoneyDetails> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

                                @Override
                                public void invoke(TAgcPayMoneyDetails data, AnalysisContext analysisContext) {
                                    if(!StringUtils.isEmpty(data.getBusinessType())) {
                                        // 截取发生日期为账单日期
                                        billDate.set(DateUtils.dateToYM(data.getCreateTime()));

                                        data.setMainId(main.getId());
                                        cachedDataList.add(data);
                                        if (cachedDataList.size() >= BATCH_COUNT) {
                                            saveData();
                                            // 存储完成清理 list
                                            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                                        }
                                    }
                                }

                                @Override
                                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                                    saveData();
                                }

                                // 保存数据库
                                private void saveData() {
                                    if (!cachedDataList.isEmpty()) {
                                        detailsMapper.batchInsert(cachedDataList);
                                    }
                                }
                            }).excelType(XLSX).charset(GBK_CHARSET).sheet().headRowNumber(1).doRead();

                            // 更新账单状态
                            main.setStatus("3");
                            main.setBillDate(billDate.get());
                            tMoneyMainMapper.update(main);
                        } catch (Exception e) {
                            main.setStatus("2");
                            tMoneyMainMapper.update(main);
                            // 通过websocket发送通知
                            WebSocketUsers.sendMessageToUserByText(main.getUserId(), excelName + " 账单上传失败，请重新上传", BusinessStatus.SUCCESS);
                            throw new RuntimeException("解析聚合账单出错，请重新上传");
                        }

                        // 通过websocket发送通知
                        WebSocketUsers.sendMessageToUserByText(main.getUserId(), excelName + " 账单上传完成", BusinessStatus.SUCCESS);

                        // 生成分类账单数据
                        summaryService.classifyMoney(main);

                    };
                    exec.execute(run);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<String> getIds(TMoneyMain tMoneyMain) {
        return tMoneyMainMapper.getIds(tMoneyMain);
    }


    private TMoneyMain createMainRecord(String rulePlatform, String excelName, String storeCode){

        // 从Redis中获取账单号对应店铺名称
        TStoreMgmt storeMgmt = RedisCacheUtils.getCacheObject(CacheConstants.STORE_REDIS_KEY + storeCode);



        TMoneyMain main = new TMoneyMain();
        main.setRulePlatform(rulePlatform);
        main.setExcelName(excelName);
        main.setStoreCode(storeCode);
        main.setUserId(SecurityUtils.getUserId());
        main.setDeptId(SecurityUtils.getDeptId());
        main.setCreateBy(SecurityUtils.getUsername());
        main.setCreateTime(new Date());
        if (storeMgmt != null) {
            main.setStoreName(storeMgmt.getFinStoreName());
        }

        tMoneyMainMapper.insert(main);

        return main;
    }


    public String getFileName(String excelName) {
        String regex = "\\((.*?)\\)";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(excelName);

        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return "";
        }
    }

    public String getAgcFileName(String excelName) {
        String regex = "-(.*?)\\.";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(excelName);

        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return "";
        }
    }
}
